﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Dotnet.Utils.Utility.AssemblyUtil
{
    public static class MemberInfoExtensions
    {
        /// <summary>
        /// 获取方法的参数名和参数类型
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public static Dictionary<string, Type> GetMethodParameterInfo(MethodInfo methodInfo)
        {
            return methodInfo.GetParameters().ToDictionary(k => k.Name, v => v.ParameterType);
        }

        /// <summary>
        /// 获取方法的返回值类型
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public static Type GetMethodReturnType(MethodInfo methodInfo)
        {
            return methodInfo.ReturnType;
        }

        /// <summary>
        /// 获取Task异步方法的返回值类型
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public static Type GetMethodTaskReturnType(MethodInfo methodInfo)
        {
            Type returnType = methodInfo.ReturnType;
            if (IsTask(returnType) && returnType.GetGenericArguments().Length > 0)
            {
                return returnType.GetGenericArguments()[0];
            }
            return returnType;
        }

        /// <summary>
        /// 判断方法是否有返回值
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public static bool HasReturnValue(MethodInfo methodInfo)
        {
            if (methodInfo.ReturnType == typeof(void))
            {
                return false;
            }
            if (typeof(Task).IsAssignableFrom(methodInfo.ReturnType) && !methodInfo.ReturnType.GetGenericArguments().Any())
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 判断是否是Task方法
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static bool IsTask(Type type)
        {
            return type == typeof(Task) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>));
        }

        /// <summary>
        /// Gets a single attribute for a member.
        /// </summary>
        /// <typeparam name="TAttribute">Type of the attribute</typeparam>
        /// <param name="memberInfo">The member that will be checked for the attribute</param>
        /// <param name="inherit">Include inherited attributes</param>
        /// <returns>Returns the attribute object if found. Returns null if not found.</returns>
        public static TAttribute? GetSingleAttributeOrNull<TAttribute>(this MemberInfo memberInfo, bool inherit = true)
            where TAttribute : Attribute
        {
            if (memberInfo == null)
            {
                throw new ArgumentNullException(nameof(memberInfo));
            }

            var attrs = memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).ToArray();
            if (attrs.Length > 0)
            {
                return (TAttribute)attrs[0];
            }

            return default;
        }

        public static TAttribute? GetSingleAttributeOfTypeOrBaseTypesOrNull<TAttribute>(this Type type, bool inherit = true)
            where TAttribute : Attribute
        {
            var attr = type.GetTypeInfo().GetSingleAttributeOrNull<TAttribute>();
            if (attr != null)
            {
                return attr;
            }

            if (type.GetTypeInfo().BaseType == null)
            {
                return null;
            }

            return type.GetTypeInfo().BaseType?.GetSingleAttributeOfTypeOrBaseTypesOrNull<TAttribute>(inherit);
        }
    }
}